﻿using System;
using System.Net;
using System.Net.Sockets;
using LiteNetLib;
using LiteNetLib.Utils;
using Protocols;
using UnityEngine;

public class GameClient
{
    private readonly SimpleNet Client = new SimpleNet();
    private readonly NetPacketProcessor NetPacketProcessor = new NetPacketProcessor();

    public Action<bool> ConnectCallback = null;
    public Action DisconnectCallback = null;

    private NetPeer ServerPeer;

    private bool ConnectChecked = false;

    private string UserName, Password;

    private IControl Controller;
    
    public bool Start(string ip, int port, string name, string passwd, IControl c)
    {
        Controller = c;
        UserName = name;
        Password = passwd;

        NetPacketProcessor.SubscribeNetSerializable<S2CLoginRes>(LoginRes);
        NetPacketProcessor.SubscribeNetSerializable<S2CLoginNtf>(LoginNtf);
        NetPacketProcessor.SubscribeNetSerializable<S2CDisconnectNtf>(DisconnectNtf);
        NetPacketProcessor.SubscribeNetSerializable<S2CPlayerMoveDataNtf>(PlayerMoveDataNtf);
        NetPacketProcessor.SubscribeNetSerializable<S2CServerStatusNtf>(ServerStatusNtf);
        NetPacketProcessor.SubscribeNetSerializable<S2CChatNtf>(ChatNtf);
        NetPacketProcessor.SubscribeNetSerializable<S2CTick>(Tick);

        var EventBasedNetListener = new EventBasedNetListener();
        EventBasedNetListener.NetworkErrorEvent += EventBasedNetListener_NetworkErrorEvent;
        EventBasedNetListener.PeerDisconnectedEvent += EventBasedNetListener_PeerDisconnectedEvent;
        EventBasedNetListener.NetworkReceiveEvent += EventBasedNetListener_NetworkReceiveEvent;
        EventBasedNetListener.PeerConnectedEvent += EventBasedNetListener_PeerConnectedEvent;

        var ret = true;
        if (!Client.Start(0, EventBasedNetListener, NetPacketProcessor, false, true, 16))
        {
            NetDebug.Log($"Client Start Error");
            ret = false;
        }
        else if (Client.NetManager.Connect(ip, port, "RoomTest") != null)
        {
            NetDebug.Log($"Client Connect Success");
        }
        else
        {
            NetDebug.Log($"Client Connect Error");
            ret = false;
        }

        return ret;
    }

    private double ServerTime = 0;
    private double OldServerTime = 0;
    public void Tick(S2CTick tick)
    {
        ServerTime = tick.Now;
        OldServerTime = ServerTime;
    }

    private readonly int TickCheck = 5; //5秒检测一次

    private float SendTick = 0f;
    //超时判断
    private void CheckServer()
    {
        ServerTime += Time.deltaTime;
        if (ServerTime - OldServerTime > TickCheck)
        {
            
        }
        
        SendTick += Time.deltaTime;
        if (SendTick > TickCheck)
        {
            SendTick = 0;
            var upload = new C2STick();
            NetPacketProcessor.SendNetSerializable(ServerPeer, ref upload, DeliveryMethod.Sequenced);
        }
    }

    public void Update()
    {
        Client.Update();

        CheckServer();
    }

    public void UploadMoveData(MoveData data)
    {
        var upload = new C2SPlayerMoveData
        {
            Data = data
        };
        NetPacketProcessor.SendNetSerializable(ServerPeer, ref upload, DeliveryMethod.Sequenced);
    }

    public void Chat(string msg)
    {
        var chat = new C2SChat
        {
            Msg = msg
        };
        NetPacketProcessor.SendNetSerializable(ServerPeer, ref chat, DeliveryMethod.Sequenced);
    }

    private void EventBasedNetListener_PeerConnectedEvent(NetPeer peer)
    {
        if (!ConnectChecked)
        {
            ConnectChecked = true;
            ConnectCallback?.Invoke(true);
        }

        ServerPeer = peer;

        var login = new C2SLogin
        {
            Name = UserName,
            Password = Password,
        };
        NetPacketProcessor.SendNetSerializable(peer, ref login, DeliveryMethod.Sequenced);
    }

    private void DisconnectNtf(S2CDisconnectNtf ntf)
    {
        NetDebug.Log($"player_{ntf.UserID} disconnected!");
        Controller?.Disconnect(ntf.UserID);
    }

    private void ServerStatusNtf(S2CServerStatusNtf ntf)
    {
        Controller?.ServerStatusChanged(ntf.OnlineCnt);
    }

    private void LoginRes(S2CLoginRes login)
    {
        Controller?.LoginResult(login);
    }

    private void LoginNtf(S2CLoginNtf ntf)
    {
        Controller?.OtherUserLogin(ntf.UserID, ntf.UserName);
    }

    private void PlayerMoveDataNtf(S2CPlayerMoveDataNtf ntf)
    {
        Controller?.PlayerMove(ntf.UserID, ntf.Data);
    }

    private void ChatNtf(S2CChatNtf ntf)
    {
        Controller?.Chat(ntf.UserID, ntf.Msg);
    }

    public void Destroy()
    {
        Client.Destroy();
    }

    private void EventBasedNetListener_NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel,
        DeliveryMethod deliveryMethod)
    {
        NetPacketProcessor.ReadAllPackets(reader, peer);
    }

    private void EventBasedNetListener_PeerDisconnectedEvent(NetPeer peer, DisconnectInfo disconnectInfo)
    {
        if (!ConnectChecked)
        {
            ConnectChecked = true;
            ConnectCallback?.Invoke(false);
        }
        DisconnectCallback?.Invoke();

        ServerPeer?.Disconnect();
        ServerPeer = null;

        NetDebug.Log($"Client Disconnected");
    }

    private void EventBasedNetListener_NetworkErrorEvent(IPEndPoint endPoint, SocketError socketError)
    {
        if (!ConnectChecked)
        {
            ConnectChecked = true;
            ConnectCallback?.Invoke(false);
        }
        DisconnectCallback?.Invoke();
        ServerPeer?.Disconnect();
        ServerPeer = null;
        NetDebug.Log($"Client Error:{socketError.ToString()}");
    }
}
